﻿using System;
using System.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Conducido.WcfMessageLogger.Services.Behaviors.Entities.Config;

namespace Conducido.WcfMessageLogger.Services.Behaviors
{
    class ClientMessagelog: BehaviorExtensionElement, IEndpointBehavior
    {

        private const string AssemblyNameAtt = "AssemblyName";
        private const string FullyQualifiedTypeNameAtt = "FullyQualifiedTypeName";
        private const string ClassNameAtt = "ClassName";
        private const string PropertyNameAtt = "PropertyName";
        private const string ShouldCorrelateAtt = "ShouldCorrelate";
        private const string HeaderNamespaceAtt = "HeaderNamespace"; //TODO: The const should move to a config const class
        private const string MessageLogTypePropertyName = "WayOfLogging";
        private const string ServiceMessageLogType = "ServiceMessageLogTransportType";
        private const string Uri = "Uri";

        private string _assemblyName;
        private string _className;
        private string _fullyQualifiedTypeName;
        private string _headerNamespace;
        private string _propertyName;
        private ServiceMessageLogType _serviceMessageLogTransportType;
        private bool _shouldCorrelate;
        private string _uri;
        private MessageLogType _wayOfLogging;

        public override Type BehaviorType
        {
            get { return typeof (ClientMessagelog); }
        }


        private ClientMessagelog(string assemblyName, string className, string fullyQualifiedTypeName,
                                  string headerNamespace, string propertyName,
                                  ServiceMessageLogType serviceMessageLogTransportType, bool shouldCorrelate, string uri,
                                  MessageLogType wayOfLogging)
        {
            _assemblyName = assemblyName;
            _className = className;
            _fullyQualifiedTypeName = fullyQualifiedTypeName;
            _headerNamespace = headerNamespace;
            _propertyName = propertyName;
            _serviceMessageLogTransportType = serviceMessageLogTransportType;
            _shouldCorrelate = shouldCorrelate;
            _uri = uri;
            _wayOfLogging = wayOfLogging;
        }

        /// <summary>
        /// Default ctor
        /// </summary>
        public ClientMessagelog()
        {}

        protected override object CreateBehavior()
        {
            return new ClientMessagelog(AssemblyName, ClassName, FullyQualifiedTypeName, HeaderNamespace, 
                PropertyName, ServiceMessageLogTransportType, ShouldCorrelate, URI, WayOfLogging);
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            //Not needed
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {

            var correlator = new ClientCorrelationInspector(CreateCorrelationConfiguration()); 
            var logger = new ClientMessagelogInspector(WayOfLogging, ServiceMessageLogTransportType, URI);

            clientRuntime.MessageInspectors.Add(correlator);
            clientRuntime.MessageInspectors.Add(logger);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            //Not needed
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            //Not needed
        }

        /// <summary>
        /// How should the behavior log
        /// </summary>
        [ConfigurationProperty(MessageLogTypePropertyName, DefaultValue = MessageLogType.Database, IsRequired = true)]
        public MessageLogType WayOfLogging
        {
            get
            {
                return (MessageLogType)base[MessageLogTypePropertyName];
            }
            set
            {
                base[MessageLogTypePropertyName] = value;
            }
        }

        /// <summary>
        /// Which transport should be used (Only needed if <see cref="MessageLogType.Service"/> has been chosen.
        /// </summary>
        [ConfigurationProperty(ServiceMessageLogType, IsRequired = false)]
        public ServiceMessageLogType ServiceMessageLogTransportType
        {
            get { return (ServiceMessageLogType)base[ServiceMessageLogType]; }
            set { base[ServiceMessageLogType] = value; }
        }

        /// <summary>
        /// Url (also used for connectionstring) 
        /// </summary>
        [ConfigurationProperty(Uri)] //TODO:connect this one for the database as well
        public string URI
        {
            get { return (string)base[Uri]; }
            set { base[Uri] = value; }
        }

        /// <summary>
        /// Name of the assembly where the correlationID should be in
        /// </summary>
        [ConfigurationProperty(AssemblyNameAtt, IsRequired = false)]
        public string AssemblyName
        {
            get { return (string)base[AssemblyNameAtt]; }
            set { base[AssemblyNameAtt] = value; }
        }

        /// <summary>
        /// FQN Typename where of the class
        /// </summary>
        [ConfigurationProperty(FullyQualifiedTypeNameAtt, IsRequired = false)]
        public string FullyQualifiedTypeName
        {
            get { return (string)base[FullyQualifiedTypeNameAtt]; }
            set { base[FullyQualifiedTypeNameAtt] = value; }
        }

        /// <summary>
        /// Name of the headerclass
        /// </summary>
        [ConfigurationProperty(ClassNameAtt, IsRequired = false)]
        public string ClassName
        {
            get { return (string)base[ClassNameAtt]; }
            set { base[ClassNameAtt] = value; }
        }

        /// <summary>
        /// The name of the property
        /// </summary>
        [ConfigurationProperty(PropertyNameAtt, IsRequired = false)]
        public string PropertyName
        {
            get { return (string)base[PropertyNameAtt]; }
            set { base[PropertyNameAtt] = value; }
        }

        /// <summary>
        /// Swith to turn it off
        /// </summary>
        [ConfigurationProperty(ShouldCorrelateAtt, IsRequired = false)]
        public bool ShouldCorrelate
        {
            get { return (bool)base[ShouldCorrelateAtt]; }
            set { base[ShouldCorrelateAtt] = value; }
        }

        /// <summary>
        /// Namespace of the header
        /// </summary>
        [ConfigurationProperty(HeaderNamespaceAtt, IsRequired = false)]
        public string HeaderNamespace
        {
            get { return (string)base[HeaderNamespaceAtt]; }
            set { base[HeaderNamespaceAtt] = value; }
        }

        private CorrelationConfiguration CreateCorrelationConfiguration()
        {
            var config = new CorrelationConfiguration
            {
                AssemblyName = _assemblyName,
                ClassName = _className,
                FullyQualifiedTypeName = _fullyQualifiedTypeName,
                HeaderNamespace = _headerNamespace,
                PropertyName = _propertyName,
                ShouldCorrelate = _shouldCorrelate
            };
            return config;
        }
    }
}
